home *** CD-ROM | disk | FTP | other *** search
- /* HDraw By Paul Kunz June 1991
- * derived from DrawApp in Draw, a NeXT, inc. example application
- * Global object for application incorporating HippoDraw.
- *
- * Copyright (C) 1991 The Board of Trustees of
- * The Leland Stanford Junior University. All Rights Reserved.
- */
-
- #import "HDraw.h"
-
- const char HDraw_h_rcsid[] = HDRAW_H_ID;
- const char HDraw_m_rcsid[] = "$Id: HDraw.m,v 1.32 1992/04/07 17:49:12 pfkeb Rel $";
-
- #import "DrawDocument.h"
- #import "HGraphicView.h"
- #import "DrawPageLayout.h"
- #import "Inspector.h"
- #import "InspectAxes.h"
- #import "InspectCut.h"
- #import "InspectData.h"
- #import "InspectPlot.h"
- #import "InspectStat.h"
- #import "InspectTuple.h"
- #import "NewInspector.h"
- #import "Plot.h"
- #import "draw.h"
-
- #import <appkit/Application.h>
- #import <appkit/Cursor.h>
- #import <appkit/Listener.h>
- #import <appkit/Matrix.h>
- #import <appkit/Menu.h>
- #import <appkit/MenuCell.h>
- #import <appkit/NXColorPanel.h>
- #import <appkit/OpenPanel.h>
- #import <appkit/Pasteboard.h>
- #import <appkit/Text.h>
- #import <appkit/defaults.h>
- #import <appkit/nextstd.h>
- #import <objc/hashtable.h> /* for NXCopyStringBuffer() */
- #import <objc/List.h>
- #import <sys/param.h>
- #import <ldsyms.h>
- #import <sys/loader.h>
- #import <libc.h>
- #import <string.h>
- #import <mach.h>
-
- const int DrawVersion = 18; /* minor version of the program */
-
- @implementation HDraw : Object
- /*
- * This class is used primarily to handle the opening of new documents
- * and other application-wide activity (such as responding to messages from
- * the tool palette). It listens for requests from the Workspace Manager
- * to open a draw-format file as well as target/action messages from the
- * New and Open... menu items. It also keeps the menus in sync by
- * fielding the menu items' updateActions.
- */
-
- /* Private C functions used to implement methods in this class. */
-
- static void initMenu(id menu)
- /*
- * Sets the updateAction for every menu item which sends to the
- * First Responder (i.e. their target is nil). When autoupdate is on,
- * every event will be followed by an update of each of the menu items
- * which is visible. This keep all unavailable menu items dimmed out
- * so that the user knows what options are available at any given time.
- * Returns the activate menu if is found in this menu.
- */
- {
- int count;
- id matrix, cell;
- id matrixTarget, cellTarget;
-
- matrix = [menu itemList];
- matrixTarget = [matrix target];
-
- count = [matrix cellCount];
- while (count--) {
- cell = [matrix cellAt:count :0];
- cellTarget = [cell target];
- if (!matrixTarget && !cellTarget) {
- [cell setUpdateAction:@selector(menuItemUpdate:) forMenu:menu];
- } else if ([cell hasSubmenu]) {
- initMenu(cellTarget);
- }
- }
- }
-
- static id documentInWindow(id window)
- /*
- * Checks to see if the passed window's delegate is a DrawDocument.
- * If it is, it returns that document, otherwise it returns nil.
- */
- {
- id document = [window delegate];
- return [document isKindOf:[DrawDocument class]] ? document : nil;
- }
-
- static id findDocument(const char *name)
- /*
- * Searches the window list looking for a DrawDocument with the specified name.
- * Returns the window containing the document if found.
- * If name == NULL then the first document found is returned.
- */
- {
- int count;
- id document, window, windowList;
-
- windowList = [NXApp windowList];
- count = [windowList count];
- while (count--) {
- window = [windowList objectAt:count];
- document = documentInWindow(window);
- if (document && (!name || !strcmp([document filename], name))) {
- return window;
- }
- }
-
- return nil;
- }
-
- static id openFile(const char *directory, const char *name, BOOL display)
- /*
- * Opens a file with the given name in the specified directory.
- * If we already have that file open, it is ordered front.
- * Returns the document if successful, nil otherwise.
- */
- {
- id window;
- char buffer[MAXPATHLEN+1], path[MAXPATHLEN+1];
-
- if (name && *name) {
- if (!directory) {
- directory = ".";
- } else if (*directory != '/') {
- strcpy(buffer, "./");
- strcat(buffer, directory);
- directory = buffer;
- }
- if (!chdir(directory) && getwd(path)) {
- strcpy(path, directory); /* to avoid /private/Net/... */
- strcat(path, "/");
- strcat(path, name);
- window = findDocument(path);
- if (window) {
- if (display) [window makeKeyAndOrderFront:window];
- return [window delegate];
- } else {
- return [DrawDocument newFromFile:path];
- }
- } else {
- NXRunAlertPanel("Open", "Invalid path: %s", "OK", NULL, NULL, directory);
- }
- }
-
- return nil;
- }
-
- /* Public methods */
-
- + initialize
- /*
- * Initializes the defaults.
- */
- {
- const NXDefaultsVector DrawDefaults = {
- { "KnobWidth", "5" },
- { "KnobHeight", "5" },
- { "KeyMotionDelta", "1"},
- { "Quit", NULL },
- { NULL, NULL }
- };
-
- NXRegisterDefaults("Draw", DrawDefaults);
-
- return self;
- }
- + allocFromZone:(NXZone *)aZone
- {
- NXZone *zone;
-
- zone = NXCreateZone(vm_page_size, vm_page_size, YES);
- NXNameZone(zone, "HippoDraw");
- self = [super allocFromZone:zone];
- return self;
- }
-
- + alloc
- {
- return [self allocFromZone:NULL];
- }
-
- - init
- /*
- * PSInit() defines all the PostScript defs we use (see draw.psw).
- * setAutoupdate:YES means that updateWindows will be called after
- * every event is processed (this is how we keep our inspector and
- * our menu items up to date).
- */
- {
- [NXApp loadNibSection:"HDraw.nib" owner:self
- withNames:YES fromZone:[self zone]];
- PSInit();
- [NXApp setAutoupdate:YES];
-
- theNewInspector = [[NewInspector allocFromZone:[self zone]] init ];
- inspectTuple = [[InspectTuple allocFromZone:[self zone]] initInspFor:self];
- inspectData = [[InspectData allocFromZone:[self zone]] initInspFor:self];
- inspectPlot = [[InspectPlot allocFromZone:[self zone]] initInspFor:self];
- inspectAxes = [[InspectAxes allocFromZone:[self zone]] initInspFor:self];
- inspectStat = [[InspectStat allocFromZone:[self zone]] initInspFor:self];
- inspectCut = [[InspectCut allocFromZone:[self zone]] initInspFor:self];
- return self;
- }
- - infoPanel:sender
- {
- if( ! infoPanel ){
- [NXApp loadNibSection:"Info.nib" owner:self
- withNames:NO fromZone:[self zone]];
- }
- [infoPanel makeKeyAndOrderFront:sender];
- return self;
- }
- - legalPanel:sender
- {
- if( ! legalPanel ){
- [NXApp loadNibSection:"Legal.nib" owner:self
- withNames:NO fromZone:[self zone]];
- }
- [legalPanel makeKeyAndOrderFront:sender];
- return self;
- }
- /* General application status and information querying/modifying methods. */
-
- - currentGraphic
- {
- return currentGraphic;
- }
-
- - currentDocument
- {
- return documentInWindow([NXApp mainWindow]);
- }
-
- - (const char *)currentDirectory
- {
- id openpanel = [OpenPanel new];
-
- const char *retval = [[self currentDocument] directory];
- if (!retval || !*retval) {
- [openpanel setDirectory:NXHomeDirectory()];
- retval = [openpanel directory];
- }
- return retval;
- }
-
- /* Application-wide shared panels */
-
- - saveToPanel
- /*
- * Returns a SavePanel with the accessory view which allows the user to
- * pick which type of file she wants to save.
- */
- {
- id savepanel = [SavePanel new];
- [savepanel setAccessoryView:savePanelAccessory];
- [spamatrix selectCellAt:0 :0];
- [savepanel setRequiredFileType:"hdraw"];
- return savepanel;
- }
-
- - saveAsPanel
- /*
- * Returns a regular SavePanel with "hdraw" as the required file type.
- */
- {
- id savepanel = [SavePanel new];
- [savepanel setAccessoryView:nil];
- [savepanel setRequiredFileType:"hdraw"];
- return savepanel;
- }
-
- - gridInspector
- /*
- * Returns the application-wide inspector for a document's grid.
- * Note that if we haven't yet loaded the GridView panel, we do it.
- * The instance variable gridInspector is set in setGridInspector:
- * since it is set as an outlet of the owner (self, i.e. DrawApp).
- */
- {
- if (!gridInspector) {
- NXZone *zone = NXCreateChildZone([self zone], vm_page_size, vm_page_size, YES);
- NXNameZone(zone, "GridView");
- [NXApp loadNibSection:"GridView.nib" owner:self withNames:NO fromZone:zone];
- NXMergeZone(zone);
- }
- return gridInspector;
- }
-
- - inspectorPanel
- /*
- * Returns the application-wide inspector for Graphics.
- */
- {
- return inspectorPanel;
- }
-
- - newInspector
- {
- return theNewInspector;
- }
- - pageLayout
- /*
- * Returns the application-wide DrawPageLayout panel.
- */
- {
- static id dpl = nil;
-
- if (!dpl) {
- dpl = [DrawPageLayout new];
- [dpl setAccessoryView:plpAccessory];
- [dpl setSideForm:[plpAccessory findViewWithTag:1]];
- [dpl setTopBotForm:[plpAccessory findViewWithTag:2]];
- }
-
- return dpl;
- }
-
- - orderFrontInspectorPanel:sender
- /*
- * Creates the inspector panel if it doesn't exist, then orders it front.
- */
- {
- id accessory;
- NXZone *zone;
- NXRect ipFrame;
-
- if (!inspectorPanel) {
- inspectorPanel = [NXColorPanel newColorMask:NX_ALLMODESMASK];
- zone = [inspectorPanel zone];
- accessory = [NXApp loadNibSection:"InspectorPanel.nib" owner:self withNames:NO fromZone:zone];
- [inspectorPanel setDelegate:[accessory delegate]];
- [inspectorPanel setAccessoryView:[[[[accessory contentView] subviews] objectAt:0] removeFromSuperview]];
- [inspectorPanel setTitle:"Inspector"];
- [inspectorPanel setMode:NX_GRAYMODE];
- [inspectorPanel setTarget:[accessory delegate]];
- [inspectorPanel setShowAlpha:NO];
- [accessory getFrame:&ipFrame];
- [inspectorPanel moveTo:ipFrame.origin.x :ipFrame.origin.y];
- [accessory free];
- [[inspectorPanel delegate] preset];
- }
- [inspectorPanel orderFront:self];
-
- return self;
- }
- - orderFrontTupleInsp:sender
- {
-
- theNewInspector = [ self newInspector];
- [theNewInspector orderFrontPanel:self];
- return self;
- }
- - inspectTuple
- {
- return inspectTuple;
- }
- - addTuple:(ntuple) nt
- {
- return [inspectTuple addTuple:nt];
- }
- - inspectPlot
- {
- return inspectPlot;
- }
- - inspectCut
- {
- return inspectCut;
- }
- - orderFrontTools:sender
- {
- [[tools window] orderFront:self];
- return self;
- }
- /* Target/Action methods */
-
- - help:sender
- {
- int size;
- char *data;
- NXStream *stream;
- id window, document;
-
- if (!(window = findDocument("/tmp/Help"))) {
- data = getsectdata("HELP", "document", &size);
- if (data) {
- stream = NXOpenMemory(data, size, NX_READONLY);
- if (stream) {
- document = [DrawDocument newFromStream:stream];
- [document setName:"Help" andDirectory:"/tmp"];
- }
- NXClose(stream);
- }
- } else {
- [window makeKeyAndOrderFront:self];
- }
-
- return self;
- }
-
- - new:sender
- /*
- * Called by pressing New in the Window menu.
- */
- {
- [DrawDocument new];
- return self;
- }
-
- - open:sender
- /*
- * Called by pressing Open... in the Window menu.
- */
- {
- const char *directory;
- const char *const *files;
- const char **myfiles;
- static const char *const drawType[2] = {"hdraw", NULL};
- id openpanel = [[OpenPanel new] allowMultipleFiles:YES];
- int i, nfiles;
-
- directory = [[self currentDocument] directory];
- if (directory && (*directory == '/')) [openpanel setDirectory:directory];
- if ([openpanel runModalForTypes:drawType]) {
- files = [openpanel filenames];
- directory = [openpanel directory];
- /*
- * we made need to use the open panel again, so need to
- * save results now is separate array
- */
- nfiles = 0;
- while ( files && *files ) {
- nfiles++;
- files++;
- }
- files = [openpanel filenames];
- NX_MALLOC( myfiles, const char *, nfiles );
- for ( i = 0; i < nfiles; i++ ) {
- myfiles[i] = NXCopyStringBuffer(*files);
- files++;
- }
- for ( i = 0; i < nfiles; i++ ) {
- haveOpenedDocument = openFile(directory, myfiles[i], YES)
- || haveOpenedDocument;
- NX_FREE( myfiles[i] );
- }
- NX_FREE( myfiles );
- }
-
- return self;
- }
- - openTuple:sender
- {
- [inspectTuple openTuple:sender];
- return self;
- }
- - openTupleAsText:sender
- {
- [inspectTuple openTupleAsText:sender];
- return self;
- }
- - openTuple:pasteBoard
- userData:(const char *)args
- error:(char **)errorMsg
- {
- [[[DrawDocument new] view] openTuple:pasteBoard
- userData:args
- error:errorMsg];
-
- return self;
- }
- - saveAll:sender
- /*
- * Saves all the documents.
- */
- {
- int count;
- id window, windowList;
-
- windowList = [NXApp windowList];
- count = [windowList count];
- while (count--) {
- window = [windowList objectAt:count];
- [documentInWindow(window) save:self];
- }
-
- return nil;
- }
-
- - terminate:sender
- /*
- * Overridden to be sure all documents get an opportunity to be saved
- * before exiting the program.
- */
- {
- int count, choice;
- id window, windowList, document;
-
- windowList = [NXApp windowList];
- count = [windowList count];
- while (count--) {
- window = [windowList objectAt:count];
- document = [window delegate];
- if ([document respondsTo:@selector(needsSaving)] && [document needsSaving]) {
- choice = NXRunAlertPanel("Quit", "You have unsaved documents.", "Review Unsaved", "Quit Anyway", "Cancel");
- if (choice == NX_ALERTOTHER) {
- return self;
- } else if (choice == NX_ALERTDEFAULT) {
- count = [windowList count];
- while (count--) {
- window = [windowList objectAt:count];
- document = [window delegate];
- if ([document respondsTo:@selector(windowWillClose:action:)]) {
- if ([document windowWillClose:window action:"Quit"]) {
- [window close];
- } else {
- return self;
- }
- }
- }
- }
- break;
- }
- }
- [NXApp terminate:sender];
-
- return nil;
- }
-
- /*
- * Application object delegate methods.
- * Since we don't have an application delegate, messages that would
- * normally be sent there are sent to the Application object itself instead.
- */
-
- - appDidInit:sender
- /*
- * Makes the tool palette not ever become the key window.
- * Check for files to open specified on the command line.
- * Initialize the menus.
- * If there are no open documents, then open a blank one.
- */
- {
- int i;
- char buffer[MAXPATHLEN+1];
- char *directory, *name, *ext;
-
- [[NXApp appListener ] setServicesDelegate:self];
- [[tools window] removeFromEventMask:NX_KEYDOWNMASK|NX_KEYUPMASK];
- [[tools window] orderFront:self];
- [[tools window] setFloatingPanel:YES];
-
- if (NXArgc > 1) {
- for (i = 1; i < NXArgc; i++) {
- strcpy(buffer, NXArgv[i]);
- ext = strrchr(buffer, '.');
- if (!ext || strcmp(ext, ".hdraw")) strcat(buffer, ".hdraw");
- name = strrchr(buffer, '/');
- if (name) {
- *name++ = '\0';
- directory = buffer;
- } else {
- name = buffer;
- directory = NULL;
- }
- haveOpenedDocument = openFile(directory, name, YES) || haveOpenedDocument;
- }
- }
-
- if (!haveOpenedDocument) [self new:self];
-
- if (NXGetDefaultValue([NXApp appName], "Quit")) {
- [NXApp activateSelf:YES];
- NXPing();
- [self terminate:self];
- }
-
- initMenu([NXApp mainMenu]);
-
- return self;
- }
-
- - (int)appOpenFile:(const char *)path type:(const char *)type
- /*
- * This method is performed whenever a user double-clicks on an icon
- * in the Workspace Manager representing a Draw program document.
- */
- {
- id currentDoc;
- char *name;
- char directory[MAXPATHLEN+1];
-
- if (type && !strcmp(type, "hdraw")) {
- strcpy(directory, path);
- name = strrchr(directory, '/');
- if (name) {
- *name++ = '\0';
- if (openFile(directory, name, YES)) {
- haveOpenedDocument = YES;
- return YES;
- }
- }
- }
-
- if ( type && !strcmp(type, "hippo") ) {
- currentDoc = [self currentDocument];
- if ( !currentDoc ) {
- currentDoc = [DrawDocument new];
- }
- [ currentDoc openTupleFile:path ];
- haveOpenedDocument = YES;
- return YES;
- }
-
- return NO;
- }
-
- - (BOOL)appAcceptsAnotherFile:sender
- /*
- * We accept any number of appOpenFile:type: messages.
- */
- {
- return YES;
- }
-
- /* Listener/Speaker remote methods */
-
- - (int)msgDirectory:(const char **)fullPath ok:(int *)flag
- {
- *fullPath = [self currentDirectory];
- if (*fullPath) {
- *flag = YES;
- } else {
- *fullPath = "";
- *flag = NO;
- }
- return 0;
- }
-
- - (int)msgVersion:(const char **)aString ok:(int *)flag
- {
- char buf[20];
-
- sprintf(buf, "2.0 (v%2d)", DrawVersion);
- *aString = NXCopyStringBuffer(buf);
- *flag = YES;
-
- return 0;
- }
-
- - (int)msgFile:(const char **)fullPath ok:(int *)flag
- {
- const char *file;
-
- file = [[self currentDocument] filename];
- if (file) {
- *fullPath = file;
- *flag = YES;
- } else {
- *fullPath = "";
- *flag = NO;
- }
-
- return 0;
- }
-
- - (BOOL)shouldRunPrintPanel:sender
- /*
- * When NXApp prints, don't bring up the PrintPanel.
- */
- {
- return NO;
- }
-
- - (int)msgPrint:(const char *)fullPath ok:(int *)flag
- {
- BOOL close;
- id document = nil;
- char *directory, *name;
- char path[MAXPATHLEN+1];
- char buffer[MAXPATHLEN+1];
-
- InMsgPrint = YES;
- strcpy(buffer, fullPath);
- name = strrchr(buffer, '/');
- if (name) {
- *name++ = '\0';
- directory = buffer;
- } else {
- name = buffer;
- directory = NULL;
- }
- if (!chdir(directory) && getwd(path)) {
- strcat(path, "/");
- strcat(path, name);
- document = [findDocument(path) delegate];
- }
- if (document) {
- close = NO;
- } else {
- document = openFile(directory, name, NO);
- if (document) haveOpenedDocument = YES;
- close = YES;
- }
- if (document && ![[document view] isEmpty]) {
- [NXApp setPrintInfo:[document printInfo]];
- [[document view] printPSCode:self];
- if (close) [[[document view] window] close];
- *flag = YES;
- } else {
- *flag = NO;
- }
- InMsgPrint = NO;
-
- return 0;
- }
-
- - (int)msgSelection:(const char **)bytes length:(int *)len
- asType:(const char *)aType ok:(int *)flag
- {
- int maxlen;
- NXStream *stream;
-
- if (!strcmp(aType, DrawPboardType)) {
- stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
- if ([[[self currentDocument] view] copySelectionToStream:stream]) {
- NXGetMemoryBuffer(stream, bytes, len, &maxlen);
- *flag = YES;
- } else {
- *flag = NO;
- }
- NXClose(stream);
- } else if (!strcmp(aType, NXPostScriptPboardType)) {
- stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
- if ([[[self currentDocument] view] copySelectionAsPS:stream]) {
- NXGetMemoryBuffer(stream, bytes, len, &maxlen);
- *flag = YES;
- } else {
- *flag = NO;
- }
- NXClose(stream);
- } else if (!strcmp(aType, NXTIFFPboardType)) {
- stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
- if ([[[self currentDocument] view] copySelectionAsTIFF:stream]) {
- NXGetMemoryBuffer(stream, bytes, len, &maxlen);
- *flag = YES;
- } else {
- *flag = NO;
- }
- NXClose(stream);
- } else {
- *flag = NO;
- }
-
- if (!*flag) {
- *bytes = "";
- *len = 0;
- }
-
- return 0;
- }
-
- - (int)msgCopyAsType:(const char *)aType ok:(int *)flag
- {
- if (!strcmp(aType, NXPostScriptPboardType) ||
- !strcmp(aType, NXTIFFPboardType) ||
- !strcmp(aType, DrawPboardType)) {
- *flag = ([[[self currentDocument] view] copy:self] ? YES : NO);
- } else {
- *flag = NO;
- }
- return 0;
- }
-
- - (int)msgCutAsType:(const char *)aType ok:(int *)flag
- {
- if (!strcmp(aType, NXPostScriptPboardType) ||
- !strcmp(aType, NXTIFFPboardType) ||
- !strcmp(aType, DrawPboardType)) {
- *flag = ([[[self currentDocument] view] cut:self] ? YES : NO);
- } else {
- *flag = NO;
- }
- return 0;
- }
-
- - (int)msgPaste:(int *)flag;
- {
- *flag = ([[[self currentDocument] view] paste:self] ? YES : NO);
- return 0;
- }
-
- - (int)msgQuit:(int *)flag
- {
- *flag = ([self terminate:self] ? NO : YES);
- return 0;
- }
-
- /* Global cursor setting */
-
- - cursor
- /*
- * This is called by DrawDocument objects who want to set the cursor
- * depending on what the currently selected tool is (as well as on whether
- * the Control key has been pressed indicating that the select tool is
- * temporarily set--see sendEvent:).
- */
- {
- id theCursor = nil;
- if (!cursorPushed) theCursor = [[self currentGraphic] cursor];
- return theCursor ? theCursor : NXArrow;
- }
-
- - sendEvent:(NXEvent *)event
- /*
- * We override this because we need to find out when the control key is down
- * so we can set the arrow cursor so the user knows she is (temporarily) in
- * select mode.
- */
- {
- if (event && event->type < NX_KITDEFINED) { /* mouse or keyboard event */
- if (event->flags & NX_CONTROLMASK) {
- if (!cursorPushed && currentGraphic) {
- cursorPushed = YES;
- [[self currentDocument] resetCursor];
- }
- } else if (cursorPushed) {
- cursorPushed = NO;
- [[self currentDocument] resetCursor];
- }
- }
-
- // return [super sendEvent:event];
- return self;
- }
-
- /* Automatic update methods */
-
- - (BOOL)menuItemUpdate:menuCell
- /*
- * Method called by all menu items which send their actions to the
- * First Responder. First, if the object which would respond were the
- * action sent down the responder chain also responds to the message
- * validateCommand:, then it is sent validateCommand: to determine
- * whether that command is valid now, otherwise, if there is a responder
- * to the message, then it is assumed that the item is valid.
- * The method returns YES if the cell has changed its appearance (so that
- * the caller (a Menu) knows to redraw it).
- */
- {
- SEL action;
- id responder, target;
- BOOL enable;
-
- target = [menuCell target];
- enable = [menuCell isEnabled];
-
- if (!target) {
- action = [menuCell action];
- responder = [NXApp calcTargetForAction:action];
- if ([responder respondsTo:@selector(validateCommand:)]) {
- enable = [responder validateCommand:menuCell];
- } else {
- enable = responder ? YES : NO;
- }
- }
-
- if ([menuCell isEnabled] != enable) {
- [menuCell setEnabled:enable];
- return YES;
- } else {
- return NO;
- }
- }
-
- - (BOOL)validateCommand:menuCell
- {
- SEL action = [menuCell action];
-
- if (action == @selector(saveAll:)) {
- return findDocument(NULL) ? YES : NO;
- }
-
- return YES;
- }
-
- /*
- * This is a very funky method and tricks of this sort are not generally
- * recommended, but this hack is done so that new Graphic subclasses can
- * be added to the program without changing even one line of code (except,
- * of course, to implement the subclass itself).
- *
- * The objective-C method objc_getClass() is used to find the factory object
- * corresponding to the name of the cell sending the setCurrentGraphic:
- * message (this is set in InterfaceBuilder using the Miscellaneous panel
- * in the Inspector window).
- *
- * Again, this is not recommended procedure, but it illustrates how
- * objective-C can be used to make some funky runtime dependent decisions.
- */
-
- - setCurrentGraphic:sender
- /*
- * The sender's name is queried. If that name corresponds to the name
- * of a class, then that class is set as the currentGraphic. If not,
- * then the select tool is put into effect.
- *
- * Modified to handle Hippo 1D and 2D plots differently. This is
- * needed until their Graphic can draw rectangle while resizing,
- * then display plot when done.
- * also avoid error message associated with selecting
- * selection tool -- Paul Kunz
- */
- {
- id cell;
- const char *className;
- int tag;
-
- cell = [sender selectedCell];
- if (cell) {
- tag = [cell tag];
- /*
- * tag = -1 for selection tool
- * = -2 for Graphic object
- * = graphictype_t for Plot object
- * tag is set with Interface Builder
- */
- if ( tag < 0 ) {
- if ( tag != (-1) ) { /* avoid selection tool */
- className = NXGetObjectName(cell);
- if (className) {
- currentGraphic = objc_getClass(className);
- } else {
- currentGraphic = nil;
- }
- } else {
- currentGraphic = nil;
- }
- if (!currentGraphic) {
- [tools selectCellWithTag:(-1)];
- }
- [[self currentDocument] resetCursor];
- } else {
- currentGraphic = [Plot class];
- [self orderFrontTupleInsp:self];
- [[[self currentDocument] view] addPlotOfType:tag];
- }
- } else {
- currentGraphic = nil;
- [tools selectCellWithTag:(-1)];
- [[self currentDocument] resetCursor];
- }
-
- return self;
- }
-
- @end
-